#include "CallsTable.h"
//using namespace std;

CallsTable::CallsTable()
{
}

CallsTable::~CallsTable()
{
} 

void CallsTable::InsertCalls(int stmt_num, PROCINDEX caller_proc, PROCINDEX callee_proc)
{
	if (callerTable.find(caller_proc)==callerTable.end())
	{
		//caller procedure not inserted before
		set<PROCINDEX> s1;
		s1.insert(callee_proc);
		callerTable[caller_proc] = s1;
	}
	else
	{
		//caller procedure inserted before
		callerTable[caller_proc].insert(callee_proc);
	}
	if (calleeTable.find(callee_proc)==calleeTable.end())
	{
		//callee procedure not inserted before
		set<PROCINDEX> s2;
		s2.insert(caller_proc);
		calleeTable[callee_proc] = s2;
	}
	else
	{
		//callee procedure inserted before
		calleeTable[callee_proc].insert(caller_proc);
	}
	if (callStmtTable.find(stmt_num)==callStmtTable.end())
	{
		callStmtTable[stmt_num] = callee_proc;
	}
	else
	{
		//should not happen, 1 statment should only be able to call 1 procedure
	}
}

PROCINDEX_ARRAY CallsTable::GetCallee(PROCINDEX caller_proc)
{
	PROCINDEX_ARRAY s;
	if (callerTable.find(caller_proc)==callerTable.end())
		return s;
	else
	{
		s=callerTable[caller_proc];
		return s;
	}
}

PROCINDEX_ARRAY CallsTable::GetCaller(PROCINDEX callee_proc)
{
	PROCINDEX_ARRAY s;
	if (calleeTable.find(callee_proc)==calleeTable.end())
		return s;
	else
	{
		s=calleeTable[callee_proc];
		return s;
	}
}

PROCINDEX_ARRAY CallsTable::RetrieveTransitiveCallee(PROCINDEX caller_proc)
{
	//get a list of transitive call from the caller procedure, query results to be put inside results set
	PROCINDEX_ARRAY result;
	if (!(callerTable.find(caller_proc)==callerTable.end()))
	{

		getByCallerIndexTHelper(caller_proc,&result,this->NO);
	}
	return result;
}

void CallsTable::getByCallerIndexTHelper(PROCINDEX caller, set<int>* tempResult, int switchAddSelf)
{
	//recursive dfs search with closed list, modified from best first search, 
	//hence able to handle recursion relative to a procedure
	//if result set is not null, eg malloc fail coz of out of memory
	if (tempResult!=NULL)
	{
		if (tempResult->find(caller)==tempResult->end())
		{
			//caller procedure has not been examined before
			//add caller to list of procedures that has been examined 
			if (switchAddSelf==YES)
				tempResult->insert(caller);

			//get list of procIndex that current proc calls
			PROCINDEX_ARRAY temp = GetCallee(caller);

			if (temp.size()>0)
			{
				//set of procedures that this procedure calls
				PROCINDEX_ARRAY::iterator it;
				for (it = temp.begin();it!=temp.end();it++)
				{
					getByCallerIndexTHelper((*it),tempResult,this->YES);
				}
			}
			else
			{
				//empty set
			}
		}
		else
		{
			//caller procedure has been examined before
			//so we do not examine it again
		}
	}
}

PROCINDEX_ARRAY CallsTable::RetrieveTransitiveCaller(PROCINDEX callee_proc)
{
	PROCINDEX_ARRAY result;
	if (!(calleeTable.find(callee_proc)==calleeTable.end()))
	{
		getByCalleeIndexTHelper(callee_proc,&result,this->NO);
	}
	return result;
}


void CallsTable::getByCalleeIndexTHelper(PROCINDEX callee, set<int>* tempResult, int switchAddSelf)
{
	//recursive dfs search with closed list, modified from best first search, 
	//hence able to handle recursion relative to a procedure
	//if result set is not null, eg malloc fail coz of out of memory
	if (tempResult!=NULL)
	{
		if (tempResult->find(callee)==tempResult->end())
		{
			//caller procedure has not been examined before
			//add caller to list of procedures that has been examined 
			if (switchAddSelf==YES)
				tempResult->insert(callee);

			//get list of procIndex that current proc calls
			PROCINDEX_ARRAY temp = GetCaller(callee);

			if (temp.size()>0)
			{
				//set of procedures that this procedure calls
				PROCINDEX_ARRAY::iterator it;
				for (it = temp.begin();it!=temp.end();it++)
				{
					getByCalleeIndexTHelper((*it),tempResult,this->YES);
				}
			}
			else
			{
				//empty set
			}
		}
		else
		{
			//caller procedure has been examined before
			//so we do not examine it again
		}
	}
}

PROCINDEX CallsTable::GetCalleeByStatement(int stmt_num)
{
	if (callStmtTable.find(stmt_num)==callStmtTable.end())
	{
		//not found
		return -1;
	}
	else
	{
		return callStmtTable[stmt_num];
	}
}